home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / zcpp_jae.zip / CPP2.C < prev    next >
C/C++ Source or Header  |  1992-07-14  |  26KB  |  893 lines

  1. /*
  2.  
  3.  
  4.  Copyright (C) 1990 Texas Instruments Incorporated.
  5.  
  6.  Permission is granted to any individual or institution to use, copy, modify,
  7.  and distribute this software, provided that this complete copyright and
  8.  permission notice is maintained, intact, in all copies and supporting
  9.  documentation.
  10.  
  11.  Texas Instruments Incorporated provides this software "as is" without
  12.  express or implied warranty.
  13.  
  14.  
  15.  *                C P P 2 . C
  16.  *
  17.  *               Process #control lines
  18.  *
  19.  * Edit history
  20.  * 13-Nov-84    MM    Split from cpp1.c
  21.  * 21-Oct-85    RMS    Do not turn on `instring' while reading #include arg.
  22.  *            Rename `token' to `tokenbuf'.
  23.  *            Flush tabs at end of #include line, like spaces.
  24.  * 16-Mar-89    LGO    Split parse_file out from doinclude, so it can be 
  25.  *                      shared by #pragma demacro.
  26.  * 20-Mar-89    LGO    Ignore command errors in non-compiled code
  27.  * 23-Mar-89    LGO    Add support for #error
  28.  * 24-Sep-89    AFM     OS2 and XENIX support.
  29.  * 19-Jan-90    DKM     MVS support 
  30.  * 23-Apr-90    MJF     Include file parsing ignore // or /* as comment
  31.  * 01-May-90    MJF     unrecognized #pragma needs to output newline
  32.  * 18-May-90    MBN     Conditional compilation for COOL to get "clean" cpp
  33.  */
  34.  
  35. #include    <stdio.h>
  36. #include    <ctype.h>
  37. #include    "cppdef.h"
  38.  
  39. #if HOST != SYS_MVS
  40. #if HOST == SYS_VMS
  41. #include        <types.h>
  42. #else
  43. #include        <sys/types.h>
  44. #endif
  45. #endif
  46.  
  47. #include    "cpp.h"
  48.  
  49. #if HOST != SYS_OS2
  50. #if HOST == SYS_VMS
  51. #include        <file.h>
  52. #else
  53. #if HOST == SYS_MVS
  54. #include        <fcntl.h>
  55. #else
  56. #include        <sys/file.h>
  57. #endif
  58. #endif
  59. #endif
  60.  
  61. #if HOST == SYS_VMS
  62. /*
  63.  * Include the rms stuff.  (We can't just include rms.h as it uses the
  64.  * VaxC-specific library include syntax that Decus CPP doesn't support.
  65.  * By including things by hand, we can CPP ourself.)
  66.  */
  67. #include    <nam.h>
  68. #include    <fab.h>
  69. #include    <rab.h>
  70. #include    <rmsdef.h>
  71. #endif
  72.  
  73. #ifdef COOL
  74. extern void define_external();      /* Define an external macro handler */
  75. #endif
  76.  
  77. /*
  78.  * Generate (by hand-inspection) a set of unique values for each control
  79.  * operator.  Note that this is not guaranteed to work for non-Ascii
  80.  * machines.  CPP won't compile if there are hash conflicts.
  81.  */
  82.  
  83. #define    L_assert    ('a' + ('s' << 1))
  84. #define    L_define    ('d' + ('f' << 1))
  85. #define    L_elif        ('e' + ('i' << 1))
  86. #define    L_else        ('e' + ('s' << 1))
  87. #define    L_endif        ('e' + ('d' << 1))
  88. #define    L_if        ('i' + (EOS << 1))
  89. #define    L_ifdef        ('i' + ('d' << 1))
  90. #define    L_ifndef    ('i' + ('n' << 1))
  91. #define    L_include    ('i' + ('c' << 1))
  92. #define    L_line        ('l' + ('n' << 1))
  93. #define    L_nogood    (EOS + (EOS << 1))    /* To catch #i        */
  94. #define    L_pragma    ('p' + ('a' << 1))
  95. #define    L_error     ('e' + ('r' << 1))
  96. #define L_undef        ('u' + ('d' << 1))
  97. #if DEBUG
  98. #define    L_debug        ('d' + ('b' << 1))    /* #debug        */
  99. #define    L_nodebug    ('n' + ('d' << 1))    /* #nodebug        */
  100. #endif
  101.  
  102. int
  103. control(counter)
  104. int        counter;    /* Pending newline counter        */
  105. /*
  106.  * Process #control lines.  Simple commands are processed inline,
  107.  * while complex commands have their own subroutines.
  108.  *
  109.  * The counter is used to force out a newline before #line, and
  110.  * #pragma commands.  This prevents these commands from ending up at
  111.  * the end of the previous line if cpp is invoked with the -C option.
  112.  */
  113. {
  114.     register int        c;
  115.     register char        *tp;
  116.     register int        hash;
  117.     char            *ep;
  118.  
  119.     /* Copy all #xxx commands to output as comments */
  120.     if (debug&2 && compiling && cflag) {
  121.       char* bufp = infile->bptr;
  122.       fputs("\n//#",stdout);
  123.       while(*bufp != '\n' && *bufp != EOS)
  124.         output(*bufp++);
  125.     }
  126.  
  127.     c = skipws();
  128.     if (c == '\n' || c == EOF_CHAR)
  129.         return (counter + 1);
  130.     if (!isdigit(c))
  131.         scanid(c);            /* Get #word to tokenbuf    */
  132.     else {
  133.         unget();            /* Hack -- allow #123 as a    */
  134.         strcpy(tokenbuf, "line");    /* synonym for #line 123    */
  135.     }
  136.     hash = (tokenbuf[1] == EOS) ? L_nogood : (tokenbuf[0] +
  137.                           (tokenbuf[2] << 1));
  138.     switch (hash) {
  139.     case L_assert:    tp = "assert";        break;
  140.     case L_define:    tp = "define";        break;
  141.     case L_elif:    tp = "elif";        break;
  142.     case L_else:    tp = "else";        break;
  143.     case L_endif:    tp = "endif";        break;
  144.     case L_if:    tp = "if";        break;
  145.     case L_ifdef:    tp = "ifdef";        break;
  146.     case L_ifndef:    tp = "ifndef";        break;
  147.     case L_include:    tp = "include";        break;
  148.     case L_line:    tp = "line";        break;
  149.     case L_pragma:    tp = "pragma";        break;
  150.     case L_error:    tp = "error";        break;
  151.     case L_undef:    tp = "undef";        break;
  152. #if DEBUG
  153.     case L_debug:    tp = "debug";        break;
  154.     case L_nodebug:    tp = "nodebug";        break;
  155. #endif
  156.     default:    hash = L_nogood;
  157.     case L_nogood:    tp = "";        break;
  158.     }
  159.     if (!streq(tp, tokenbuf))
  160.         hash = L_nogood;
  161.     /*
  162.      * hash is set to a unique value corresponding to the
  163.      * control keyword (or L_nogood if we think it's nonsense).
  164.      */
  165. #ifdef PARANOID
  166.     if (infile->fp == NULL)
  167.         cwarn("Control line \"%s\" within macro expansion", tokenbuf);
  168. #endif
  169.     if (!compiling) {            /* Not compiling now    */
  170.         switch (hash) {
  171.         case L_if:                /* These can't turn    */
  172.         case L_ifdef:            /*  compilation on, but    */
  173.         case L_ifndef:            /*   we must nest #if's    */
  174.         if (++ifptr >= &ifstack[BLK_NEST])
  175.             goto if_nest_err;
  176.         *ifptr = 0;            /* !WAS_COMPILING    */
  177.         case L_line:            /* Many            */
  178.         case L_pragma:            /*  options        */
  179.         case L_include:            /*   are uninteresting    */
  180.         case L_define:            /*    if we        */
  181.         case L_undef:            /*     aren't        */
  182.         case L_assert:            /*      compiling.    */
  183.         case L_error:
  184.         case L_nogood:
  185. dump_line:    skipnl();            /* Ignore rest of line    */
  186.         return (counter + 1);
  187.         }
  188.     }
  189.     /*
  190.      * Make sure that #line and #pragma are output on a fresh line.
  191.      */
  192.     if (counter > 0 && (hash == L_line || hash == L_pragma)) {
  193.         putchar('\n');
  194.         counter--;
  195.     }
  196.     switch (hash) {
  197.     case L_line:
  198.         /*
  199.          * Parse the line to update the line number and "progname"
  200.          * field and line number for the next input line.
  201.          * Set wrongline to force it out later.
  202.          */
  203.         c = skipws();
  204.         workp = work;            /* Save name in work    */
  205.         while (c != '\n' && c != EOF_CHAR) {
  206.         save(c);
  207.         c = get();
  208.         }
  209.         unget();              /* put the newline back */
  210.         save(EOS);
  211.         /*
  212.          * Split #line argument into <line-number> and <name>
  213.          * We subtract 1 as we want the number of the next line.
  214.          */
  215.         line = atoi(work);            /* Reset line number    */
  216.         for (tp = work; isdigit(*tp) || type[*tp] == SPA; tp++)
  217.         ;                /* Skip over digits    */
  218.         if (*tp != EOS) {            /* Got a filename, so:    */
  219.         if (*tp == '"' && (ep = strrchr(tp + 1, '"')) != NULL) {
  220.             tp++;            /* Skip over left quote    */
  221.             *ep = EOS;            /* And ignore right one    */
  222.         }
  223.         if (infile->progname != NULL)    /* Give up the old name    */
  224.             free(infile->progname);    /* if it's allocated.    */
  225.             infile->progname = savestring(tp);
  226.         }
  227.         if (infile->fp == NULL) {        /* If inside a macro */
  228.           printf("#%s %d \"%s\"\n", LINE_PREFIX, line,
  229.              (infile->progname != NULL)
  230.              ? ESCNAME(infile->progname) : ESCNAME(infile->filename));
  231.           counter--;          /* Subtract for the \n added later */
  232.           wrongline = FALSE;
  233.         } else {
  234.           wrongline = TRUE;          /* else Force output later */
  235.           line--;
  236.         }
  237.         break;
  238.  
  239.     case L_include:
  240.         doinclude();
  241.         break;
  242.  
  243.     case L_define:
  244.         dodefine();
  245.         break;
  246.  
  247.     case L_undef:
  248.         doundef();
  249.         break;
  250.  
  251.     case L_else:
  252.         if (ifptr == &ifstack[0])
  253.         goto nest_err;
  254.         else if ((*ifptr & ELSE_SEEN) != 0)
  255.         goto else_seen_err;
  256.         *ifptr |= ELSE_SEEN;
  257.         if ((*ifptr & WAS_COMPILING) != 0) {
  258.         if (compiling || (*ifptr & TRUE_SEEN) != 0)
  259.             compiling = FALSE;
  260.         else {
  261.             compiling = TRUE;
  262.         }
  263.         }
  264.         break;
  265.  
  266.     case L_elif:
  267.         if (ifptr == &ifstack[0])
  268.         goto nest_err;
  269.         else if ((*ifptr & ELSE_SEEN) != 0) {
  270. else_seen_err:    cerror("#%s may not follow #else", tokenbuf);
  271.         goto dump_line;
  272.         }
  273.         if ((*ifptr & (WAS_COMPILING | TRUE_SEEN)) != WAS_COMPILING) {
  274.         compiling = FALSE;        /* Done compiling stuff    */
  275.         goto dump_line;            /* Skip this clause    */
  276.         }
  277.         doif(L_if);
  278.         break;
  279.  
  280.     case L_if:
  281.     case L_ifdef:
  282.     case L_ifndef:
  283.         if (++ifptr >= &ifstack[BLK_NEST])
  284. if_nest_err:    cfatal("Too many nested #%s statements", tokenbuf);
  285.         *ifptr = WAS_COMPILING;
  286.         doif(hash);
  287.         break;
  288.  
  289.     case L_endif:
  290.         if (ifptr == &ifstack[0]) {
  291. nest_err:    cerror("#%s must be in an #if", tokenbuf);
  292.         goto dump_line;
  293.         }
  294.         if (!compiling && (*ifptr & WAS_COMPILING) != 0)
  295.         wrongline = TRUE;
  296.         compiling = ((*ifptr & WAS_COMPILING) != 0);
  297.         --ifptr;
  298.         break;
  299.  
  300.     case L_assert:
  301.         if (eval() == 0)
  302.         cerror("Preprocessor assertion failure", NULLST);
  303.         break;
  304.  
  305.     case L_pragma:
  306.         /*
  307.          * #pragma is provided to pass "options" to later
  308.          * passes of the compiler.  cpp only has one: defmacro
  309.          */
  310.         c=skipws();
  311.         c = macroid(c);
  312. #ifdef COOL
  313.         if(strcmp(tokenbuf, "defmacro") == 0) {
  314.           define_external();
  315.  
  316. #if (HOST == SYS_XENIX || HOST == SYS_OS2)
  317. /*
  318.  * munge pack(n) for Xenix and os2 Glockenspiels cfront by quotifying 
  319.  * pack(n) to "pack(n)"
  320.  */
  321.         } else if (strcmp(tokenbuf, "pack") == 0) {
  322.           fputs("#pragma \"", stdout);
  323.           while (c != '\n' && c != EOF_CHAR) {
  324.         if (type[c] == LET) {
  325.           fputs(tokenbuf, stdout);
  326.         } else cput(c);
  327.         c = get();
  328.         c = macroid(c);
  329.           }
  330.           putchar('"');
  331.           unget();              /* Leave newline in buffer */
  332. #endif
  333.         } else
  334. #endif
  335.         { /* pass through undefined pragmas */
  336.           fputs("#pragma ", stdout);
  337.           while (c != '\n' && c != EOF_CHAR) {
  338.         if (type[c] == LET) {
  339.           fputs(tokenbuf, stdout);
  340.         } else cput(c);
  341.         c = get();
  342.         c = macroid(c);
  343.           }
  344.           putchar('\n');          /* output newline */
  345.           unget();              /* Leave newline in buffer */
  346.         }
  347.         break;
  348.  
  349.       case L_error:
  350.         workp = work;
  351.         for(c=skipws(); c!='\n' && c!=EOF_CHAR; c=get())
  352.           *workp++ = c;          
  353.         *workp = EOS;
  354.         unget();
  355.         cerror(work, NULLST);
  356.         break;
  357.  
  358. #if DEBUG
  359.     case L_debug:
  360.         if (debug == 0)
  361.         dumpdef("debug set on");
  362.         debug++;
  363.         break;
  364.  
  365.     case L_nodebug:
  366.         debug--;
  367.         break;
  368. #endif
  369.  
  370.     default:
  371.         /*
  372.          * Undefined #control keyword.
  373.          * Note: the correct behavior may be to warn and
  374.          * pass the line to a subsequent compiler pass.
  375.          * This would allow #asm or similar extensions.
  376.          */
  377.         cerror("Illegal # command \"%s\"", tokenbuf);
  378.         break;
  379.     }
  380.     if (hash != L_include) {
  381. #if OLD_PREPROCESSOR
  382.         /*
  383.          * Ignore the rest of the #control line so you can write
  384.          *        #if    foo
  385.          *        #endif    foo
  386.          */
  387.         goto dump_line;            /* Take common exit    */
  388. #else
  389.         switch (hash) {
  390.         case L_else:
  391.         case L_endif:
  392.           goto dump_line;            /* Take common exit    */
  393.         default:
  394.           if (skipws() != '\n') {
  395.         cwarn("Unexpected text in #control line ignored", NULLST);
  396.         skipnl();
  397.           }
  398.         }
  399. #endif
  400.     }
  401.     return (counter + 1);
  402. }
  403.  
  404. FILE_LOCAL
  405. doif(hash)
  406. int        hash;
  407. /*
  408.  * Process an #if, #ifdef, or #ifndef.  The latter two are straightforward,
  409.  * while #if needs a subroutine of its own to evaluate the expression.
  410.  *
  411.  * doif() is called only if compiling is TRUE.  If false, compilation
  412.  * is always supressed, so we don't need to evaluate anything.  This
  413.  * supresses unnecessary warnings.
  414.  */
  415. {
  416.     register int        c;
  417.     register int        found;
  418.  
  419.     if ((c = skipws()) == '\n' || c == EOF_CHAR) {
  420.         unget();
  421.         goto badif;
  422.     }
  423.     if (hash == L_if) {
  424.         unget();
  425.         found = (eval() != 0);    /* Evaluate expr, != 0 is  TRUE    */
  426.         hash = L_ifdef;        /* #if is now like #ifdef    */
  427.     }
  428.     else {
  429.         if (type[c] != LET)        /* Next non-blank isn't letter    */
  430.         goto badif;        /* ... is an error        */
  431.         found = (lookid(c) != NULL); /* Look for it in symbol table    */
  432.     }
  433.     if (found == (hash == L_ifdef)) {
  434.         compiling = TRUE;
  435.         *ifptr |= TRUE_SEEN;
  436.     }
  437.     else {
  438.         compiling = FALSE;
  439.     }
  440.     return;
  441.  
  442. badif:    cerror("#if, #ifdef, or #ifndef without an argument", NULLST);
  443. #if !OLD_PREPROCESSOR
  444.     skipnl();                /* Prevent an extra    */
  445.     unget();                /* Error message    */
  446. #endif
  447.     return;
  448. }
  449.  
  450. /*
  451.  * Parse the file name in the #INCLUDE control line.
  452.  * Leave the file name in work, and return the terminating delimiter
  453.  * which is " or >. Returns EOS on error.
  454.  */
  455. int
  456. parse_include()
  457. {
  458.     register int        c;
  459.     register int        delim;
  460.  
  461.     delim = macroid(skipws());
  462.     if (delim != '<' && delim != '"') {
  463.       strcpy(work, tokenbuf);
  464. #if HOST == SYS_VMS
  465.       return(' ');
  466. #else
  467.       return(EOS);
  468. #endif
  469.     }
  470.     if (delim == '<')
  471.         delim = '>';
  472.     workp = work;
  473.                                     /* Grab the file name           */
  474.         instring = TRUE;        /* ignore comment chars in filename */
  475.     while ((c = get()) != delim) {
  476.       if(c=='\n' || c == EOF_CHAR) {
  477.         instring = FALSE;
  478.         return(EOS); /* Missing delimiter */
  479.       }
  480.       else 
  481.         save(c);            /* Put it away.            */
  482.     }
  483.         instring = FALSE;
  484.     *workp = EOS;            /* Terminate filename        */
  485.     return(delim);
  486. }
  487.  
  488. FILE_LOCAL
  489. doinclude()
  490. /*
  491.  * Process the #include control line.
  492.  * There are three variations:
  493.  *    #include "file"        search somewhere relative to the
  494.  *                current source file, if not found,
  495.  *                treat as #include <file>.
  496.  *    #include <file>        Search in an implementation-dependent
  497.  *                list of places.
  498.  *    #include token        Expand the token, it must be one of
  499.  *                "file" or <file>, process as such.
  500.  *
  501.  * Note: the November 12 draft forbids '>' in the #include <file> format.
  502.  * This restriction is unnecessary and not implemented.
  503.  */
  504. {
  505.   register int        c;
  506.   register int        delim;
  507. #ifdef VMS
  508.   char                  def_filename[NAM$C_MAXRSS + 1];
  509. #endif
  510.   /* Get the file name into work  */
  511.   if((delim = parse_include()) == EOS) goto incerr;
  512.   c = skipws();
  513.   if (c != '\n' && c != EOF_CHAR)
  514.     goto incerr;         /* Ensure nothing else to end of the line. */
  515.   unget();             /* Force nl after include                 */
  516. #if HOST == SYS_VMS
  517.   /*
  518.    * Assume the default .h filetype.
  519.    */
  520.   if (!vmsparse(work, ".H", def_filename)) {
  521.     perror(work);              /* Oops.            */
  522.     goto incerr;
  523.   }
  524. #endif
  525.  
  526. #if HOST == SYS_MVS
  527.   if (findinclude_mvs(work, R_OK) == FALSE)
  528.     goto openerr;
  529. #else
  530.   if (findinclude(work, (delim == '"'), R_OK) == FALSE)
  531.     goto openerr;
  532. #endif
  533.   /*
  534.    * Actually open the include file
  535.    */
  536.  
  537.   if (debug&1) {
  538.     FILEINFO* file;              /* DEBUG */
  539.     fprintf(stderr, "Line %4d", line);
  540.     for(file = infile; file != NULL; file = file->parent)
  541.       if(file->fp != NULL) fprintf(stderr, "  ");
  542.     fprintf(stderr, "#include %s\n", work);
  543.   }
  544.   if (openfile(work))
  545.     return;
  546.   /*
  547.    * No sense continuing if #include file isn't there.
  548.    */
  549.  openerr:
  550.    cfatal("Cannot open include file \"%s\"", work);
  551.         
  552.  incerr:    cerror("#include syntax error", NULLST);
  553.   return;
  554. }
  555.  
  556.  
  557. #if HOST == SYS_OS2
  558. /* 
  559.  * Ensure dir names and filename is less than 8 characters long
  560.  */
  561. char* truncate_filename(filename) 
  562.   char* filename;
  563. {
  564.   char* p = filename;
  565.   int   name_len = 0;
  566.   char* dot;
  567.   int   slash;
  568.  
  569.   slash = strcspn(p,"/\\");
  570.   while (strlen(p) != slash)
  571.     {
  572.      if (slash == 0)    /* slash at start of name */
  573.         slash = strcspn(++p,"/\\");
  574.  
  575.      if (strlen(p) != slash)  /* slash found */
  576.        {
  577.         if (slash < 9)        /* dir name within bounds */
  578.            p += slash + 1;
  579.         else                  /* else trnucate to eight */
  580.       {
  581.            strcpy(p+8,p+slash);
  582.            p += slash + 1;
  583.      }
  584.         slash = strcspn(p,"/\\");  /* find next slash */
  585.       }
  586.    }
  587.  
  588.   dot = strchr(filename, '.');
  589.   if (dot != NULL) {
  590.     p = dot -1;
  591.     while (p >= filename && type[*p]==LET) p--, name_len++;
  592.     if (name_len > 8)
  593.       strcpy(p+9, dot);
  594.   }
  595.   return filename;
  596. }
  597. #endif
  598.  
  599. int
  600. findinclude(filename, searchlocal, permissions)
  601. char        *filename;        /* Input file name        */
  602. int        searchlocal;        /* TRUE if #include "file"    */
  603. int             permissions;            /* std permission flags, R_OK, etc */
  604. /*
  605.  * Find an include file.  This routine is only called from
  606.  * doinclude() above, but was written as a separate subroutine for
  607.  * programmer convenience.  It searches the list of directories
  608.  * and modifies filename to contain the entire pathname.
  609.  * Returns TRUE if the file was found, else FALSE.
  610.  * No error message is printed.
  611.  */
  612. {
  613.     register char        **incptr;
  614. #if HOST == SYS_VMS
  615. #if NBUFF < (NAM$C_MAXRSS + 1)
  616.     << error, NBUFF isn't greater than NAM$C_MAXRSS >>
  617. #endif
  618. #endif
  619.     char            tmpname[NBUFF];    /* Filename work area    */
  620.  
  621. /*
  622.  * For OS/2 truncate file name to eight chars
  623.  */
  624. #if HOST == SYS_OS2
  625.    truncate_filename(filename);
  626. #endif
  627.  
  628.     if (searchlocal) {
  629.         /*
  630.          * Look in local directory first
  631.          */
  632.         if (!hasdirectory(filename, tmpname, TRUE)
  633.          && hasdirectory(infile->filename, tmpname, TRUE))
  634.         strcat(tmpname, filename);
  635.         else {
  636.         strcpy(tmpname, filename);
  637.         }
  638.         if (access (tmpname, permissions) == 0) {
  639.                 strcpy(filename, tmpname);
  640.         return (TRUE);
  641.             }
  642.     }
  643.     /*
  644.      * Look in any directories specified by -I command line
  645.      * arguments, then in the builtin search list.
  646.      */
  647.     for (incptr = incdir; incptr < incend; incptr++) {
  648.         if (strlen(*incptr) + strlen(filename) >= (NBUFF - 1))
  649.         cfatal("Filename work buffer overflow", NULLST);
  650.         else {
  651. #if (HOST == SYS_UNIX || HOST == SYS_XENIX)
  652.         if (filename[0] == '/')
  653.             strcpy(tmpname, filename);
  654.         else {
  655.             sprintf(tmpname, "%s/%s", *incptr, filename);
  656.         }
  657. #else
  658. #if (HOST == SYS_OS2)
  659.         if ((filename[0] == '\\') || (filename[0] == '/'))
  660.             strcpy(tmpname, filename);
  661.         else {
  662.             sprintf(tmpname, "%s\\%s", *incptr, filename);
  663.         }
  664. #else
  665.         if (!hasdirectory(filename, tmpname, FALSE))
  666.             sprintf(tmpname, "%s%s", *incptr, filename);
  667. #endif
  668. #endif
  669.             if (access (tmpname, permissions) == 0) {
  670.                    strcpy(filename, tmpname);
  671.            return (TRUE);
  672.                 }
  673.         }
  674.     }
  675.     return (FALSE);
  676. }
  677.  
  678. #if HOST == SYS_MVS
  679.  
  680. /* convert (unix) include string into suitable mvs string for fopen.
  681.  * "foo"             ==> "syslib(foo)"
  682.  * "foo.h"           ==> "syslib(foo)"
  683.  * "foo.hxx"         ==> "syslib(foo)"
  684.  * "foo.xxx"         ==> "xxx(foo)"
  685.  * "ddname/foo"      ==> "ddname(foo)"
  686.  * "ddname/foo.h"    ==> "ddname(foo)"
  687.  * "ddname/foo.xxx"  ==> "ddname(foo)"
  688.  *
  689.  */
  690. void parse_mvs(filename) 
  691.   char *filename;                        /* This get clobbered!!! */
  692. {
  693.   char tmpname[NBUFF];             /* Filename work area    */
  694.   char *dot, *dotstr, *slash, *memname, *sp;
  695.  
  696.   strcpy(tmpname,filename);         /* copy to work buffer */
  697.   dot   = strrchr(tmpname, '.');     /* find location of "." */
  698.   slash = strrchr(tmpname, '/');     /* find location of "/" */
  699.   dotstr = dot+1;                        /* points at string following dot */
  700.  
  701.   /* first see if a unix style directory node has been specified
  702.    * If so, terminate the string at the "/" and copy max of 8 chars.
  703.    * Note that multiple directory nodes will not work.  This overrides
  704.    * any ddname specified via the dot.
  705.    */
  706.   memname = tmpname;             /* init memname to beg of string */
  707.   if (slash != NULL) {
  708.     memname = slash+1;             /* point member name after slash  */
  709.     *slash = EOS;             /* terminate ddname at slash */
  710.     if (strlen(tmpname) > 8)         /* truncate to 8 chars */
  711.       *(tmpname+8) = EOS;
  712.     strcpy(filename,tmpname);         /* copy ddname from dir node */
  713.     if (dot != 0)             /* get rid of text beyond dot */
  714.       *dot = EOS;
  715.   }
  716.   else
  717.     /* see if a ddname has been specified (ignore .h and .hxx so
  718.      * they don't get interpretted as a ddname).
  719.      * Limit to max of 8 chars
  720.      */
  721.     if (dot != NULL) {             /* if dot found*/
  722.       *dot = EOS;                        /* terminate memname at dot */
  723.       sp = strchr(dotstr,' ');         /* see if any trailing spaces */
  724.       if (sp != NULL)             /* if there are */
  725.     *sp = EOS;             /*   get rid of them */
  726.       if ((strcmp(dotstr,"h") == 0) ||     /* ignore .h */
  727.       (strcmp(dotstr,"hxx") == 0) )  /*   or  .hxx */
  728.     strcpy(filename,"syslib");     /*  and default to syslib */
  729.       else {
  730.     if (strlen(dotstr) > 8)         /* truncate ddname to 8 chars */
  731.       *(dotstr+8) = EOS;
  732.     strcpy(filename, dotstr);     /* add ddname to string */
  733.       }
  734.     }
  735.     else
  736.       strcpy(filename,"syslib");     /* default syslib ddname */
  737.  
  738. /* Add the include file name as parenthesized member name
  739.   strcat(filename, "(" );
  740.   sp = strchr(memname,' ');         /* see if any trailing spaces */
  741.   if (sp != NULL)             /* if spaces found */
  742.     *sp = EOS;                 /*   get rid of them */
  743.   if (strlen(memname) > 8)         /* truncate to 8 chars */
  744.     *(memname+8) = EOS;
  745.   strcat(filename, memname);         /* add include name */
  746.   strcat(filename, ")" );
  747.   return;
  748. }
  749.   
  750. /* MVS does not handle a -I search list of include files.  Instead
  751.  * it will allocate one or more logical DD names which point to a cancatenated
  752.  * list of include libraries. Convert include string into suitable
  753.  * MVS style string, and see if that member is there.
  754.  */
  755. int
  756. findinclude_mvs (filename, permissions)
  757. char        *filename;        /* Input file name        */
  758. int             permissions;            /* std permission flags, R_OK, etc */
  759. {
  760.   parse_mvs(filename);
  761.   if (access (filename, permissions) == 0) 
  762.     return (TRUE);
  763.   else
  764.     return (FALSE);
  765. }
  766.  
  767.  
  768. #endif
  769.  
  770. FILE_LOCAL int
  771. hasdirectory(source, result, is_toplevel)
  772. char        *source;    /* Directory to examine            */
  773. char        *result;    /* Put directory stuff here        */
  774. int             is_toplevel;    /* return true only when a complete path */
  775. /*
  776.  * If a device or directory is found in the source filename string, the
  777.  * node/device/directory part of the string is copied to result and
  778.  * hasdirectory returns TRUE.  Else, nothing is copied and it returns FALSE.
  779.  */
  780. {
  781. #if (HOST == SYS_UNIX || HOST == SYS_XENIX)
  782.     char* tp = strrchr(source, '/');
  783.     if (is_toplevel ? (source[0] != '/') : (tp == NULL))
  784.       return (FALSE);
  785.     strncpy(result, source, tp - source + 1);
  786.     result[tp - source + 1] = EOS;
  787.     return (TRUE);
  788. #else
  789. #if (HOST == SYS_OS2)
  790.     char* tp = strrchr(source, '\\');
  791.     if (is_toplevel ? (source[0]  != '\\') : (tp == NULL))
  792.       return (FALSE);
  793.     strncpy(result, source, tp - source + 1);
  794.     result[tp - source + 1] = EOS;
  795.     return (TRUE);
  796. #else
  797. #if HOST == SYS_VMS
  798.     if (vmsparse(source, NULLST, result)
  799.      && result[0] != EOS)
  800.         return (TRUE);
  801.     else {
  802.         return (FALSE);
  803.     }
  804. #else
  805.     /*
  806.      * Random DEC operating system (RSX, RT11, RSTS/E)
  807.      */
  808.     register char        *tp;
  809.  
  810.     if ((tp = strrchr(source, ']')) == NULL
  811.      && (tp = strrchr(source, ':')) == NULL)
  812.         return (FALSE);
  813.     else {
  814.         strncpy(result, source, tp - source + 1);
  815.         result[tp - source + 1] = EOS;
  816.         return (TRUE);
  817.     }
  818. #endif
  819. #endif
  820. #endif
  821. }
  822.  
  823. #if HOST == SYS_VMS
  824.  
  825. /*
  826.  * EXP_DEV is set if a device was specified, EXP_DIR if a directory
  827.  * is specified.  (Both set indicate a file-logical, but EXP_DEV
  828.  * would be set by itself if you are reading, say, SYS$INPUT:)
  829.  */
  830. #define DEVDIR (NAM$M_EXP_DEV | NAM$M_EXP_DIR)
  831.  
  832. FILE_LOCAL int
  833. vmsparse(source, defstring, result)
  834. char        *source;
  835. char        *defstring;    /* non-NULL -> default string.        */
  836. char        *result;    /* Size is at least NAM$C_MAXRSS + 1    */
  837. /*
  838.  * Parse the source string, applying the default (properly, using
  839.  * the system parse routine), storing it in result.
  840.  * TRUE if it parsed, FALSE on error.
  841.  *
  842.  * If defstring is NULL, there are no defaults and result gets
  843.  * (just) the node::[directory] part of the string (possibly "")
  844.  */
  845. {
  846.     struct FAB    fab = cc$rms_fab;    /* File access block    */
  847.     struct NAM    nam = cc$rms_nam;    /* File name block    */
  848.     char        fullname[NAM$C_MAXRSS + 1];
  849.     register char    *rp;            /* Result pointer    */
  850.  
  851.     fab.fab$l_nam = &nam;            /* fab -> nam        */
  852.     fab.fab$l_fna = source;            /* Source filename    */
  853.     fab.fab$b_fns = strlen(source);        /* Size of source    */
  854.     fab.fab$l_dna = defstring;        /* Default string    */
  855.     if (defstring != NULLST)
  856.         fab.fab$b_dns = strlen(defstring);    /* Size of default    */
  857.     nam.nam$l_esa = fullname;        /* Expanded filename    */
  858.     nam.nam$b_ess = NAM$C_MAXRSS;        /* Expanded name size    */
  859.     if (sys$parse(&fab) == RMS$_NORMAL) {    /* Parse away        */
  860.         fullname[nam.nam$b_esl] = EOS;    /* Terminate string    */
  861.         result[0] = EOS;            /* Just in case        */
  862.         rp = &result[0];
  863.         /*
  864.          * Remove stuff added implicitly, accepting node names and
  865.          * dev:[directory] strings (but not process-permanent files).
  866.          */
  867.         if ((nam.nam$l_fnb & NAM$M_PPF) == 0) {
  868.         if ((nam.nam$l_fnb & NAM$M_NODE) != 0) {
  869.             strncpy(result, nam.nam$l_node, nam.nam$b_node);
  870.             rp += nam.nam$b_node;
  871.             *rp = EOS;
  872.         }
  873.         if ((nam.nam$l_fnb & DEVDIR) == DEVDIR) {
  874.             strncpy(rp, nam.nam$l_dev, nam.nam$b_dev + nam.nam$b_dir);
  875.             rp += nam.nam$b_dev + nam.nam$b_dir;
  876.             *rp = EOS;
  877.         }
  878.         }
  879.         if (defstring != NULLST) {
  880.         strncpy(rp, nam.nam$l_name, nam.nam$b_name + nam.nam$b_type);
  881.         rp += nam.nam$b_name + nam.nam$b_type;
  882.         *rp = EOS;
  883.         if ((nam.nam$l_fnb & NAM$M_EXP_VER) != 0) {
  884.             strncpy(rp, nam.nam$l_ver, nam.nam$b_ver);
  885.             rp[nam.nam$b_ver] = EOS;
  886.         }
  887.         }
  888.         return (TRUE);
  889.     }
  890.     return (FALSE);
  891. }
  892. #endif
  893.